#pragma once

//#include <Eigen/Geometry>
#include "Eigen.h"
#include <Eigen/SVD>
#include "Graphics/BaseCamera.hpp"
#include "PerspectiveProjection.hpp"
#include "OrthographicProjection.hpp"
#include <Core/VectorUtils.hpp>

using namespace rtrt;
class MatrixCamera : public BaseCamera
{
public:
	/*!
     * Creates new matrix camera.
     * \note Rotation around Z axis will be rejected!
     * \param position Camera position
     * \param rotation Camera rotation
     */
	MatrixCamera( const Eigen::Vector3f& position = Eigen::Vector3f::Zero(),
		const Eigen::Vector3f& view = Eigen::Vector3f::UnitZ(), const Eigen::Vector3f& up = Eigen::Vector3f::UnitY(),
		const Eigen::Vector3f& right = Eigen::Vector3f::UnitX());
	~MatrixCamera(void);

	/*! Returns camera transformation in general form. */
	Eigen::Transform3f transform() const;
	/*! Sets camera transformation in general form. */
	void setTransform( const Eigen::Transform3f &transform );

	/*! Rotates the camera in world space (using Euler angles). */
	void rotate( const Eigen::Vector3f &delta );
	/*! Translates the camera in local space (x-right, y-up, z-view). */
	void translate( const Eigen::Vector3f &delta );

	/*! Returns view vector of the camera. */
	Eigen::Vector3f view() const;
	/*! Returns up vector of the camera. */
	Eigen::Vector3f up() const;
	/*! Returns right vector of the camera. */
	Eigen::Vector3f right() const;

	void setView(Eigen::Vector3f view);
	void setUp(Eigen::Vector3f up);
	void setRight(Eigen::Vector3f right);

private:
	Vector3f mView;
	Vector3f mUp;
	Vector3f mRight;
	void setRotation( const Vector3f& rotation );
};

/*! Declares matrix camera object with perspective projection. */
typedef PerspectiveProjection< MatrixCamera > PerspectiveMatrixCamera;

/*! Declares matrix camera object with orthographic projection. */
typedef OrthographicProjection< MatrixCamera > OrthographicMatrixCamera;
